use crate::helpers::{
    count_ttr, create_ttr, /*count_ttr, create_ttr,*/ link_finder, redirect_frontends,
    remove_tracking_parameters, wrap_url,
};
use std::sync::Arc;
use db::{models::Post, Db};
use urlexpand::unshorten;
//  use ActiveValue::NotSet;
use anyhow::Result;
use log::info;
use matrix_sdk::ruma::events::room::message::RoomMessageEventContent;
use tokio_stream::StreamExt;
// use futures::S
use matrix_sdk::{room::Room, ruma::events::room::message::OriginalSyncRoomMessageEvent, Client};

use url::Url;

/// Add new url to the db and belong it to user
pub async fn add(
    ev: OriginalSyncRoomMessageEvent,
    text: String,
    room: Room,
    _client: Client,
    db: Db,
) -> Result<()> {
    let urls = link_finder(text.clone());
    if urls.is_empty() {
        info!("no urls in message!")
    }
    let mut urls = tokio_stream::iter(urls);
    // let db = connect_to_db().await?;
    let user_id = ev.sender.as_str();
    println!("{user_id:#?}");
    let user_id = {
        if let Some(user_id) = db.find_user_matrix(user_id).await.unwrap() {
            user_id
        } else {
            db.create_user_matrix(user_id).await.unwrap()
        }
    };

    while let Some(url) = urls.next().await {
        let db = db.clone();
        let room = room.clone();
        // let text = text.clone();
        tokio::spawn(async move {
            if let Ok(mut url) = Url::parse(&url) {
                let rules_file = std::env::var("CLEAR_URL_FILE").unwrap();
                let clearurl = clearurl::UrlCleaner::from_file(&rules_file).await.unwrap();
                clearurl.clear(&url.as_str()).await;
                // remove_tracking_parameters(&mut url);
                let page_data = get_real_url(&url).await;
                let real_url_str = page_data.url.as_str();

                let post = {
                    if let Some(post) = db.find_post(real_url_str).await.unwrap() {
                        post
                    } else {
                        let post = create_post(page_data).await.unwrap();
                        db.create_post(&post).await.unwrap();
                        post
                    }
                };
                let userpost = {
                    if let Some(userpost_id) = db.find_user_post(user_id, post.id()).await.unwrap()
                    {
                        userpost_id
                    } else {
                        // UserPostInfo{
                        //     id,
                        //     favorite: false,
                        //     read: false
                        // }
                        db.create_user_post(post.id(), url.as_str(), user_id)
                            .await
                            .unwrap()
                    }
                };
                // let content = RoomMessageEventContent::text_plain(url.to_string());

                // println!("sending");

                // send our message to the room we found the "!party" command in
                // the last parameter is an optional transaction id which we don't
                // care about.
                // room.send(content, None).await.unwrap();

                // println!("message sent");
                // bot.send_message(telegram_user.id, url.to_string())
                //     .reply_markup(keyboards::standart_keyboard(
                //         &post_id.to_hyphenated().to_string(),
                //         user_post_info.read,
                //         user_post_info.favorite,
                //     ))
                //     .await?;
                // If post does not exist, create it

                // let event_id = ev.event_id.to_string();
                log::info!("Successful saved post");
                // create_message_event(userpost_id, &db, event_id).await.unwrap();
                let mut answer = {
                    let url_str = url.as_str();
                    if let Some(title) = post.title() {
                        wrap_url(url_str, &title)
                    } else {
                        url_str.to_string()
                    }
                };
                let ttr = count_ttr(post.word_count());
                if let Some(ttr) = ttr {
                    create_ttr(&mut answer, ttr)
                };

                let content = RoomMessageEventContent::text_markdown(answer);

                println!("sending");

                // send our message to the room we found the "!party" command in
                // the last parameter is an optional transaction id which we don't
                // care about.
                let response = room.send(content).await.unwrap();
                let event_id = response.event_id.to_string();
                db.create_message_event(userpost.id(), event_id)
                    .await
                    .unwrap();
                dbg!(response);

                println!("message sent");
            };
        });
    }

    //println!("{:#?}", ev);
    //  let urls = link_finder(&text);
    // if urls.is_empty() {
    //     info!("No urls in the message!");
    // }
    // info!("Urls in the message: {:#?}", urls);
    // let db = connect_to_db()
    //     .await
    //     .context("Error while connecting to db:")?;
    // let telegram_user = m.from().context("Error while get telegram user data:")?;
    // let user_id = telegram_user.id;
    // let user_username = telegram_user.username.clone();
    // };
    // for mut url in urls {
    //     remove_tracking_parameters(&mut url);
    //     let mut real_url = real_url(&url).await;
    //     remove_tracking_parameters(&mut real_url);
    //     // If post exists, see if it belongs to the user.
    //     if let Ok(post_id) = post_exists(&real_url, &db).await {
    //         if let Some(user_post_info) =
    //             check_duplicates_in_post_map(user_id, post_id, &db, &url).await?
    //         {
    //             bot.send_message(telegram_user.id, url.to_string())
    //                 .reply_markup(keyboards::standart_keyboard(
    //                     &post_id.to_hyphenated().to_string(),
    //                     user_post_info.read,
    //                     user_post_info.favorite,
    //                 ))
    //                 .await?;
    //         }
    //         // If post does not exist, create it
    //     } else {
    //         let post = create_post(real_url).await?;
    //         save_post_to_db(&post, &db).await?;
    //         append_post_to_user(user_id, post.id(), &db, url.as_str()).await?;
    //         let _post_id = post.id();

    //         log::info!("Successful saved post");
    //         let mut answer = {
    //             let url_str = url.as_str();
    //             if let Some(title) = post.title() {
    //                 wrap_url(url_str, &title)
    //             } else {
    //                 escape(&escape_link_url(url_str))
    //             }
    //         };
    //         let ttr = count_ttr(post.word_count);
    //         if let Some(ttr) = ttr {
    //             create_ttr(&mut answer, ttr)
    //         };
    //         bot.send_message(telegram_user.id, answer)
    //             .reply_markup(keyboards::standart_keyboard(
    //                 &post.id().to_hyphenated().to_string(),
    //                 false,
    //                 false,
    //             ))
    //             //   .parse_mode(ParseMode::MarkdownV2)
    //             .await?;
    //     }
    // }

    Ok(())
}
// use url::Url;
// // Open web page using reqwest and get final url
pub struct FetchPage {
    url: Url,
    html: Vec<u8>,
}
use reqwest::Client as ReqwestClient;
use std::{io::Read, time::Duration};
async fn get_real_url(original_url: &Url) -> FetchPage {
    let proxy = std::env::var("PROXY").unwrap();
    let proxy = reqwest::Proxy::https(proxy).unwrap();
    let timeout = Duration::from_secs(10);
    let mut real_url = None;
    let mut html = None;
    // match un
    if let Ok(url) = unshorten(original_url.as_str(), Some(timeout), Some(proxy.clone())).await {
        real_url = Some(Url::parse(&url).unwrap());
    }
    let request = ReqwestClient::builder()
        .proxy(proxy)
        .build()
        .unwrap()
        .get(original_url.to_owned())
        .timeout(timeout)
        .send()
        .await;
    if let Ok(res) = request {
        if real_url.is_none() {
            real_url = Some(res.url().to_owned())
        }
        html = Some(res.text().await.unwrap().as_bytes().to_vec());
    }
    FetchPage {
        url: {
            match real_url {
                Some(url) => url,
                None => original_url.to_owned(),
            }
        },
        html: match html {
            Some(html) => html,
            None => Vec::new(),
        },
    }

    //     info!("{url}");
    //     real_url = url;
    //     FetchPage{
    //         url,
    //         Default::default();
    //     }
    // } else if let Ok(res) = ReqwestClient::builder()
    //     .proxy(proxy)
    //     .build()
    //     .unwrap()
    //     .get(original_url.to_owned())
    //     .timeout(timeout)
    //     .send()
    //     .await
    // {
    //     //TODO: work with url
    //     real_url = res.url().to_owned();
    //     // let html = ;
    //     info!("{}", real_url);
    //     FetchPage{
    //         url: real_url,
    //         html: res.text().await.unwrap().as_bytes().to_vec()
    //     }
    // } else {
    //     // info!("{:#?}", e);
    //     FetchPage{
    //     url: original_url.to_owned(),
    //     html: Default::default()
    //     }
    // }
}
use time::OffsetDateTime;

fn created() -> OffsetDateTime {
    OffsetDateTime::now_utc()
}
async fn create_post(page_data: FetchPage) -> Result<Post> {
    let created = created();
    let alternative_url = redirect_frontends(&page_data.url);
    let id = uuid::Uuid::new_v4();
    // let mut title = None;
    // let mut word_count = None;
    let parser_output = parser::parse(
        Arc::new(page_data.url.clone()),
        //&mut page_data.html.as_slice(),
        "mercury:3000",
        "http://readability:3020",
    )
    .await?;
    // let post = Post::builder()
    //     .id(id)
    //     .created(created)
    //     .real_url(real_url.to_string())
    //     .title(parser_output.title)
    //     .word_count(parser_output.duration.map(|s| s.seconds() as i64))
    //     .alternative_url(alternative_url.map(|s| s.to_string()))
    //     .build();
    let post = Post::new(
        id,
        parser_output.title,
        parser_output.duration.map(|s| s.seconds() as i64),
        page_data.url.to_string(),
        alternative_url.map(|s| s.to_string()),
        created,
    );
    Ok(post)
}
